package jp.androidgroup.chiba.androidresearch.aws;

import java.util.ArrayList;
import java.util.List;

import com.amazonaws.services.simpledb.AmazonSimpleDBClient;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import jp.androidgroup.chiba.androidresearch.Common;
import jp.androidgroup.chiba.androidresearch.Constants;
import jp.androidgroup.chiba.androidresearch.data.Counter;
import jp.androidgroup.chiba.androidresearch.db.DatabaseHelper;

public class CounterManage {
	private boolean isLetestCounterData = false;
	private final static int SDB_QUERY_LIMIT = 15;
	private DatabaseHelper mHelper;
	private SQLiteDatabase mDb;
	private AmazonSimpleDBClient mSdb;
	private String mFirstKey = null;
	private String mLastKey = null;
	private String mEmail;
	private String mLatestCreateDate;
	private SharedPreferences mPref;
	private boolean isNextData;
	private boolean isBackData;

	/**
	 * コンストラクタ
	 */
	public CounterManage(Context cont, DatabaseHelper helper, SQLiteDatabase db) throws Exception{
		mHelper = helper;
		mDb = db;
		mSdb = Sdb.getSdb(cont);

		// プリファレンスを用意する
		mPref = cont.getSharedPreferences(Constants.PREF_NAME , Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);

		// 現在、SQLiteで保持しているCounterのCreateDateの最新日
		mLatestCreateDate = mPref.getString(Constants.PREF_COUNTER_LATEST_CREATE_DATE, null);

		// 現在ログインしているユーザのメールアドレス
		// mEmail = "test@test.ne.jp";
		mEmail = Common.getUserInfo().getEmail();
	}

	/**
	 * 次のデータの有無
	 * @return isNextData
	 */
	public boolean isNextData() {
		return isNextData;
	}

	/**
	 * 前のデータの有無
	 * @return isBackData
	 */
	public boolean isBackData() {
		return isBackData;
	}

	/*
	 * 次のデータ取得
	 *
	 * number:取得する件数
	 *
	 * return:取得したデータ
	 */
	@SuppressWarnings("unchecked")
	public  List<Counter> next(int number) throws Exception{
		int detailno;
		int counternum;
		String key;
		String query;
		String selection = null;
		List<Counter> list;
		List<Counter> tmplist;

		list = new ArrayList<Counter>();

		if(isLetestCounterData == false){
			// 最新版データの取得
			getSdbLetestCounterData();
			isLetestCounterData = true;
		}

		if(mLastKey != null){
			selection = "Key < '" + mLastKey + "'";
		}

		// 投稿日時　降順、KEY()　昇順でデータを取得する
		// 投稿日と、グループkeyでグループ化したデータを取得する
		tmplist = (List<Counter>) mHelper.find(mDb, Counter.class, new String[]{"key"}, selection, "key", null, "Key DESC", String.valueOf(number));
		counternum = tmplist.size();

		// 明細を取得する
		for(int i = 0;i < tmplist.size();i++){
			selection = "Key = '" + tmplist.get(i).getKey() + "'";
			list.addAll((List<Counter>) mHelper.find(mDb, Counter.class, null, selection, null, null, " DetailNo ASC", null));
		}

		// 最後行のkeyを取得
		if(list.size() > 0){
			mLastKey = list.get(list.size() - 1).getKey();
		}

		// 取得しようとした件数に満たしていない場合は、SDBから取得する
		while(counternum < number){
			selection = "where Key is not null";
			if(mLastKey != null){
				selection += " and Key < '" + mLastKey + "'";
			}

			// SDBからデータを取得する
			// とりあえず各Counterの明細数がわからないので、SDB_QUERY_LIMI分取得する(Order byは1つしか指定できない；)
			query = "select * from " + Sdb.getDomainName(Counter.class) + " " + selection + " order by Key DESC Limit " + String.valueOf(SDB_QUERY_LIMIT);
			Log.i(Common.LOT_TAG, query);
			tmplist = (List<Counter>) Sdb.selectQuery(mSdb, query, new Counter());

			if(tmplist.size() > 0){
				// 最後の方は、すべての明細が取得できているか確認する
				detailno = 0;
				key = tmplist.get(tmplist.size() - 1).getKey();
				for(int i = tmplist.size() -1;i >= 0;i--){
					if(tmplist.get(i).getKey().equals(key)){
						detailno += 1;
					}
				}

				// 明細数と、カウントした明細数が異なれば、全明細が取得できていないと判断
				// 残りの明細を取得する
				if(Integer.parseInt(tmplist.get(tmplist.size() - 1).getDetailNo()) != detailno){
					selection = "where Key = '" +  tmplist.get(tmplist.size() - 1).getKey() +  "'";
					for(int i = tmplist.size() -1;i >= 0;i--){
						selection += " and ItemName() != '" + tmplist.get(i).getKey() + "'";
					}
					// 対象のグループを再度取り直し
					query = "select * from " + Sdb.getDomainName(Counter.class) + " " + selection+ " order by Key DESC";
					tmplist.addAll((List<Counter>) Sdb.selectQuery(mSdb, query, new Counter()));
				}
			}else{
				// SDBには取得するデータはないと判断
				Log.i(Common.LOT_TAG, "Not found");
				break;
			}

			key = "";
			for(int i = 0;i < tmplist.size();i++){
				if(!key.equals(tmplist.get(i).getKey())){
					counternum += 1;
					Log.i(Common.LOT_TAG, "counternum:" + String.valueOf(counternum));
				}
				mHelper.save(mDb, tmplist.get(i));
				if(counternum <= number){
					list.add(tmplist.get(i));
				}
				key = tmplist.get(i).getKey();
			}
			// 最後に取得したグループキーを保持
			if(list.size() > 0){
				mLastKey = list.get(list.size() - 1).getKey();
			}
		}

		// 最初のグループキーを保持
		if(list.size() > 0){
			mFirstKey = list.get(0).getKey();
		}else{
			mLastKey = null;
			mFirstKey = null;
		}

		// 次のデータ有無の確認
		isExistData();

		return getCounterList(list);
	}

	/*
	 * 前のデータを取得する
	 *
	 * number:取得する件数
	 */
	@SuppressWarnings("unchecked")
	public List<Counter> back(int number) throws Exception{
		String selection;
		List<Counter> list;
		List<Counter> tmplist;

		list = new ArrayList<Counter>();

		if(isLetestCounterData == false){
			// 最新版データの取得
			getSdbLetestCounterData();
			isLetestCounterData = true;
		}

		// mLastKeyがnullということはありえないはず
		if(mFirstKey != null){
			selection = "Key > '" + mFirstKey + "'";
			Log.i(Common.LOT_TAG,"FirstKey:" + mFirstKey);
			tmplist = (List<Counter>) mHelper.find(mDb, Counter.class, new String[]{"key"}, selection, "key", null, "Key ASC", String.valueOf(number));
			Log.i(Common.LOT_TAG,"Size:" + String.valueOf(tmplist.size()));

			// 明細を取得する
			for(int i = tmplist.size() - 1;i >=0;i--){
				selection = "Key = '" + tmplist.get(i).getKey() + "'";
				list.addAll((List<Counter>) mHelper.find(mDb, Counter.class, null, selection, null, null, " DetailNo ASC", null));
			}
		}

		// 最初と最後のグループキーを保持
		if(list.size() > 0){
			mFirstKey = list.get(0).getKey();
			mLastKey = list.get(list.size() - 1).getKey();
		}else{
			mFirstKey = null;
			mLastKey = null;
		}

		// 次のデータ有無の確認
		isExistData();

		return getCounterList(list);
	}

	/*
	 * SDBのCounter最新SDBデータを取得する
	 */
	@SuppressWarnings("unchecked")
	public void getSdbLetestCounterData() throws Exception{
		Editor edit;
		String query;
		List<Counter> sdblist;

		if(mLatestCreateDate != null){
			// 自分が投稿したデータ以外に、自分が持っているCounterの最新作成日時(CreateDate)よりも、最新のデータがSDBにあるか確認する
			// これをする理由として、後日、過去の日付で投稿した場合のことを考えて
			query = "select * from " + Sdb.getDomainName(Counter.class) + " where Email != '" + mEmail + "' and CreateDate > '" + mLatestCreateDate + "' and CreateDate is not null order by CreateDate";
			sdblist = (List<Counter>)Sdb.selectQuery(mSdb, query , new Counter());
			for(int i = 0;i < sdblist.size();i++){
				mHelper.save(mDb, sdblist.get(i));
			}
			if(sdblist.size() > 0){
				mLatestCreateDate = sdblist.get(sdblist.size() - 1).getCreateDate();
			}
		}else{
			mLatestCreateDate = Common.getNowDate();
		}

		// プリファレンスに最新の作成日時を設定する
		edit = mPref.edit();
		edit.putString(Constants.PREF_COUNTER_LATEST_CREATE_DATE, mLatestCreateDate);
		edit.commit();
	}

	/*
	 * 次のデータ有無の確認
	 */
	private void isExistData() throws Exception{
		Cursor cursor1;
		Cursor cursor2;
		String query;
		String selection;

		// 次のデータが存在するか確認する
		selection = "where Key is not null";
		if(mLastKey != null){
			selection += " and Key < '" + mLastKey + "'";
		}
		query = "select count(*) from %s " + selection;
		Log.i(Common.LOT_TAG,"next query:" + query);

		// SQLiteにあるか確認
		cursor1 = mDb.rawQuery(String.format(query, Counter.class.getSimpleName()), null);
		cursor1.moveToFirst();
		isNextData = (cursor1.getInt(0) > 0);
		if(!isNextData){
			// SDBにあるか確認
			isNextData = (Sdb.queryCount(mSdb, String.format(query, Sdb.getDomainName(Counter.class))) > 0);
		}
		cursor1.close();
		Log.i(Common.LOT_TAG,"NextData:" + isNextData);

		// 前のデータが存在するか確認する
		if(mFirstKey != null){
			selection = "where Key is not null and Key > '" + mFirstKey + "'";
			query = "select count(*) from %s " + selection ;

			Log.i(Common.LOT_TAG,"back query:" + query);
			// SQLiteにあるか確認
			cursor2 = mDb.rawQuery(String.format(query, Counter.class.getSimpleName()), null);
			cursor2.moveToFirst();
			isBackData = (cursor2.getInt(0) > 0);
			cursor2.close();
		}else{
			isBackData = false;
		}
		Log.i(Common.LOT_TAG,"BackData:" + isBackData);
	}

	/*
	 * 明細のCounterリストを、投稿単位に変換
	 */
	private List<Counter> getCounterList(List<Counter> list){
		String key;
		List<Counter> counterlist;

		key = "";
		counterlist = new ArrayList<Counter>();
		for(int i = 0;i < list.size();i++){
			if(!list.get(i).getKey().equals(key)){
				counterlist.add(list.get(i));
				counterlist.get(counterlist.size() - 1).setDetails(new ArrayList<Counter>());
				key = list.get(i).getKey();
			}
			counterlist.get(counterlist.size() - 1).getDetails().add(list.get(i));
		}

		return counterlist;
	}
}